// 封装 axios
import axios from 'axios'
import store from '@/store'
import { Toast } from 'antd-mobile'
import { customHistory } from './history'
import { clearToken, setToken } from './token'

const baseURL = 'http://toutiao.itheima.net/v1_0'

const http = axios.create({
  baseURL,
  timeout: 5000
})

// 将来可以继续进行 拦截器 的处理

// 请求拦截器
http.interceptors.request.use(config => {
  // 获取token
  // 注意：极客园h5项目中，login 存储的是一个对象，对象中的 token 属性，才是登录身份令牌
  const {
    login: { token }
  } = store.getState()

  // 除了登录请求外，其他请求统一添加 token
  if (!config.url?.startsWith('/authorizations')) {
    // 此处，需要使用 非空断言 来去掉 headers 类型中的 undefined 类型
    config.headers!.Authorization = `Bearer ${token}`
  }

  return config
})

// 响应拦截器
http.interceptors.response.use(undefined, async error => {
  // 响应失败时，会执行此处的回调函数
  if (!error.response) {
    // 网路超时
    Toast.show({
      content: '网络繁忙，请稍后再试',
      duration: 1000
    })
    return Promise.reject(error)
  }

  // 在此处，通过 refresh_token 来换取新的 token
  if (error.response.status === 401) {
    try {
      // ...
      // 先判断 redux 中是否有 refresh_token
      const { refresh_token } = store.getState().login
      if (!refresh_token) {
        // console.log('refresh_token 没有了')
        // // 本地没有
        // Toast.show({
        //   content: '登录超时，请重新登录',
        //   duration: 1000,
        //   afterClose: () => {
        //     customHistory.push('/login', {
        //       from: customHistory.location.pathname
        //     })
        //   }
        // })

        // return Promise.reject(error)

        // 1 手动抛出异常
        // throw new Error(error)

        // 2 因为 try-catch 无法直接捕获 Promise 的异常，所以，此处
        //   通过 await 等待 Promise 完成。然后，try-catch 就可以
        //   捕获到该异常了
        await Promise.reject(error)
      }

      // 有 refresh_token，就用 refresh_token 换取新的 token
      // 注意：
      //  1 此处需要使用 axios 发请求
      //  2 因为使用的是 axios 所以，此处需要指定完整的 接口路径
      //  3 对于 put 请求来来说，第 3 个参数才表示配置项，才能够设置 请求头
      //  4 此处的请求头用的是 refresh_token 而不是 token
      const res = await axios.put(`${baseURL}/authorizations`, null, {
        headers: {
          Authorization: `Bearer ${refresh_token}`
        }
      })

      // console.log(res)
      // 使用新拿到的 token 替换本地的 token 以及 redux 中的 token
      // 组装所有 token
      const tokens = {
        // token 是最新的，接口返回的
        token: res.data.data.token,
        // 因为接口没有返回新的 refresh_token，所以，需要使用原来的
        refresh_token
      }
      setToken(tokens)
      store.dispatch({ type: 'login/token', payload: tokens })

      // 继续完成原来要执行的操作
      // 比如，在获取个人资料时，token 超时了，最终，在拿到最新的 token 后
      //      要继续获取个人资料
      // console.dir(error)
      // 可以通过 error.config 来拿到原来发送的请求的相关信息
      // 所以，要执行原来的操作，只需要将 error.config 重新请求一次即可
      // 注意：此处，一定要返回 Promise 的结果
      return http(error.config)
    } catch (e) {
      // 如果换取新 token 的过程中，代码出错了，一般就说明 refresh_token 失效了
      // 此时，就清空token然后返回登录页面
      // 注意：在直接分发 thunk action 时，会报类型错误
      // store.dispatch(logout())
      // 解决方式：先自己手动分发对象形式的 action 来实现退出
      store.dispatch({ type: 'login/logout' })
      // 手动清理本地的 token
      clearToken()

      Toast.show({
        content: '登录超时，请重新登录',
        duration: 1000,
        afterClose: () => {
          customHistory.push('/login', {
            from: customHistory.location.pathname
          })
        }
      })

      return Promise.reject(error)
    }
  }
})

export { http }
